

 #include <sys/types.h>          /* See NOTES */
 #include <sys/socket.h>
 #include <sys/select.h>
 #include<netinet/in.h>

#include <dpl/log.h>
#include <dpl/config.h>


D_LOG_DOMAIN(select_test,"this is a case, how to use");

#define UDP_PORT	51234


enum
{
    READ_FDS,
    WRITE_FDS,
    EXCEPT_FDS
};


/*
 * do_select()
 *
 * Perform dpl_sock_select() and find out which sockets
 * are signalled.
 */    
static int do_select( dpl_sock_t sock1, dpl_sock_t sock2,
		      int setcount[])
{
    fd_set fds[3];
    dpl_time_val timeout;
    int i, n;
    
    for (i=0; i<3; ++i) {
        FD_ZERO(&fds[i]);
        FD_SET(sock1, &fds[i]);
        FD_SET(sock2, &fds[i]);
        setcount[i] = 0;
    }

    timeout.sec = 1;
    timeout.msec = 0;

    n = select(DPL_IOQUEUE_MAX_HANDLES, &fds[0], &fds[1], &fds[2],
		       &timeout);
    if (n < 0)
        return n;
    if (n == 0)
        return 0;

    for (i=0; i<3; ++i) {
        if (FD_ISSET(sock1, &fds[i]))
            setcount[i]++;
        if (FD_ISSET(sock2, &fds[i]))
	    setcount[i]++;
    }

    return n;
}



/*
 * select_test()
 *
 * Test main entry.
 */
int test_select()
{
	dpl_i("Enter test!");
    dpl_sock_t udp1=-1, udp2=-1;
    struct sockaddr_in udp_addr;
    int status;
    int setcount[3];
    dpl_str_t s;
    const char data[] = "hello";
    const int datalen = 5;
    dpl_ssize_t sent, received;
    char buf[10];
    dpl_status_t rc;

    dpl_i ("...Testing simple UDP select()");
    
    // Create two UDP sockets.
    udp1 = socket( AF_INET, SOCK_DGRAM, 0);
    if (udp1<0) {
        dpl_e("...error: unable to create socket", rc);
	status=-10; goto on_return;
    }
    udp2 = socket( AF_INET, SOCK_DGRAM, 0);
    if (udp2 <0) {
        dpl_e("...error: unable to create socket", rc);
	status=-20; goto on_return;
    }

    // Bind one of the UDP socket.
    bzero(&udp_addr, sizeof(udp_addr));
    udp_addr.sin_family = AF_INET;
    udp_addr.sin_port = UDP_PORT;
   // udp_addr.sin_addr = inet_addr( "127.0.0.1");
    udp_addr.sin_addr.s_addr = inet_addr( "127.0.0.1");
	
    if (bind(udp2, &udp_addr, sizeof(udp_addr))) {
	status=-30; goto on_return;
    }

    // Send data.
    sent = datalen;
    rc = sendto(udp1, data, sent, 0, &udp_addr, sizeof(udp_addr));
    if (rc <0 || sent != datalen) {
        dpl_e("...error: sendto() error", rc);
	status=-40; goto on_return;
    }

    // Sleep a bit. See http://trac.dplsip.org/repos/ticket/890
    dpl_thread_sleep(10);

    // Check that socket is marked as reable.
    // Note that select() may also report that sockets are writable.
    status = do_select(udp1, udp2, setcount);
    if (status < 0) {
	char errbuf[128];
        //dpl_strerror(dpl_get_netos_error(), errbuf, sizeof(errbuf));
	dpl_e( "...error: %s", errbuf);
	status=-50; goto on_return;
    }
    if (status == 0) {
	status=-60; goto on_return;
    }

    if (setcount[READ_FDS] != 1) {
	status=-70; goto on_return;
    }
    if (setcount[WRITE_FDS] != 0) {
	if (setcount[WRITE_FDS] == 2) {
	    dpl_i( "...info: system reports writable sockets");
	} else {
	    status=-80; goto on_return;
	}
    } else {
	dpl_i( "...info: system doesn't report writable sockets");
    }
	
    if (setcount[EXCEPT_FDS] != 0) {
		status=-90; goto on_return;
    }

    // Read the socket to clear readable sockets.
    received = sizeof(buf);
    rc = recv(udp2, buf, received, 0);
    if (rc  != 5) {
		dpl_d("%d",rc);
	status=-100; goto on_return;
    }
    //dpl_d("");
    status = 0;

    // Test timeout on the read part.
    // This won't necessarily return zero, as select() may report that
    // sockets are writable.
    setcount[0] = setcount[1] = setcount[2] = 0;
    status = do_select(udp1, udp2, setcount);
    if (status != 0 && status != setcount[WRITE_FDS]) {
	dpl_i( "...error: expecting timeout but got %d sks set",
			     status);
	dpl_i( "          rdset: %d, wrset: %d, exset: %d",
			     setcount[0], setcount[1], setcount[2]);
	status = -110; goto on_return;
    }
    if (setcount[READ_FDS] != 0) {
	dpl_i( "...error: readable socket not expected");
	status = -120; goto on_return;
    }

    status = 0;
//dpl_i("run over!");
on_return:
    if (udp1 != -1)
	close(udp1);
    if (udp2 != -1)
	close(udp2);
    return status;
}

